Railsアプリでセキュアなパスワードを使用する方法 +α 。
準備
gem追加
Gemfileを修正し、bundle install
します。
Railsアプリを rails new
で作成後に特に消していなければ、Blowfish暗号を利用できる bcrypt
というgemがコメントアウトされているはずです。
これをアンコメントします。
## 省略 ##
- # gem 'bcrypt', '~> 3.1.7'
+ gem 'bcrypt', '~> 3.1.7'
## 省略 ##
bundle install
実装
セキュアなパスワードは has_secure_password
というメソッドを、生成されるmodelで呼び出します。
このメソッドを使うためには、モデル内に password_digest
という属性が含まれている必要があるため注意します。
モデル作成
rails g model User name:string email:string password_digest:string
modelファイル編集
app/models/user.rb
に下記を追加します。
before_save
... オブジェクトの保存直前に実行has_secure_password
... 前述validates
... バリデーション処理
class User < ApplicationRecord
before_save { email.downcase! }
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i.freeze
# 半角英数字大文字小文字をそれぞれ1文字以上含む
VALID_PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,16}+\z/.freeze
validates :name,
presence: true,
length: { in: 1..30 }
validates :email,
presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password,
presence: true,
length: { minimum: 8 },
format: { with: VALID_PASSWORD_REGEX }
end
Migration
$ rails db:migrate
invoke active_record
create db/migrate/20190829085116_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
確認
User.new
で作成したオブジェクトを save
メソッドで保存。
ハッシュ化されたパスワードが登録されていることを確認します。
$ rails c
Loading development environment (Rails 5.2.3)
irb(main):001:0> user = User.new(name: "kohbis", email: "tEst@test.com", password: "Passw0rd")
=> #<User id: nil, name: "kohbis", email: "tEst@test.com", password_digest: "$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.1...", created_at: nil, updated_at: nil>
irb(main):002:0> user.save
(0.9ms) BEGIN
User Exists (1.3ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'tEst@test.com' LIMIT 1
User Create (0.5ms) INSERT INTO `users` (`name`, `email`, `password_digest`, `created_at`, `updated_at`) VALUES ('kohbis', 'test@test.com', '$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.18p.sIGQ/Ce', '2019-08-29 12:39:14', '2019-08-29 12:39:14')
(2.2ms) COMMIT
=> true
irb(main):003:0> User.all
User Load (0.9ms) SELECT `users`.* FROM `users` LIMIT 11
=> #<ActiveRecord::Relation [#<User id: 1, name: "kohbis", email: "test@test.com", password_digest: "$2a$12$pPsDOoJErpVXsdtLWNoGvOTdmUFBSGk/nf492aA0N.1...", created_at: "2019-08-29 12:39:14", updated_at: "2019-08-29 12:39:14">]>
最後にvalidationが効いているかも確認しておきます。
$ rails c
Loading development environment (Rails 5.2.3)
irb(main):001:0> user = User.new(name: "", email: "@not.address", password: "password")
(0.6ms) SET NAMES utf8, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
=> #<User id: nil, name: "", email: "@not.address", password_digest: "$2a$12$5PovSBWfHCPDOKQcD3lCAuOC7YepZvIwIaocF01tEI5...", created_at: nil, updated_at: nil>
irb(main):002:0> user.valid?
User Exists (0.5ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = '@not.address' LIMIT 1
=> false
irb(main):003:0> user.errors.messages
=> {:name=>["can't be blank", "is too short (minimum is 1 character)"], :email=>["is invalid"], :password=>["is invalid"]}
以上。